package com.mall.malladminbackend.filters;

import com.mall.malladminbackend.enums.JwtValidateInfo;
import com.mall.malladminbackend.utils.JwtUtils;
import com.google.common.base.Joiner;
import lombok.AllArgsConstructor;
import net.sf.jsqlparser.statement.select.Join;
import org.apache.catalina.security.SecurityUtil;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 前端能够传递给服务器端只有 jwt, 那么 spring security 拿到 jwt之后，以 security方式认为我们登录过：
 *    处理方式就是从JWT 中提取用户的信息，然后封装出一个 UsernamePasswordAuthenticationToken 这样一个对象，
 *    还需要将其添加到 security 的上下文中，那么security就认为我们登录了，那么就可以访问需要登录才能访问的接口。
 */
public class JwtFilter extends OncePerRequestFilter {

    private JwtUtils jwtUtils;

    public void setJwtUtils(JwtUtils jwtUtils) {
        this.jwtUtils = jwtUtils;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String uri = request.getRequestURI();
        // 因为登录不需要携带 jwt
        if("/login".equals(uri)) {
            filterChain.doFilter(request, response);
            return;
        }else {
            //非登录接口必须要携带 jwt
            String jwt = request.getHeader("Authorization");
            // null != jwt && !"".equals(jwt)
            if(StringUtils.hasText(jwt)) {  // jwt有值
                JwtValidateInfo info = jwtUtils.validateJwt(jwt);
                switch (info.getStatus()) {
                    // 正确
                    case correct:
                        String subject = info.getSubject();  // 用户名信息
                        List<String> authorizes = info.getAuthorizes(); // 用户的权限
                        // 将权限转换为 List<SimpleGrantedAuthority>
                        // List<SimpleGrantedAuthority> grantedAuthorities = authorizes.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList());
                        // 将字符串自动的转换 List<SimpleGrantedAuthority> 这样一个集合
//                        AuthorityUtils.commaSeparatedStringToAuthorityList("user:view,user:delete");

                        /**
                         * 1.第一个参数是用户名
                         * 2.第二个参数是密码，可以不用写，但是不能写 null, 可以写上一个 ""
                         * 3.第三个参数，与权限有关，后续在讲到授权的时候在说这个参数。
                         */
                        UsernamePasswordAuthenticationToken token  = new UsernamePasswordAuthenticationToken(subject, "",
                                AuthorityUtils.commaSeparatedStringToAuthorityList(Joiner.on(",").join(authorizes)));
                        // 将请求的信息也设置到这个token中。
                        token.setDetails(new WebAuthenticationDetails(request));
                        // spring中带 XXXHolder 表示 XXX的持有器。
                        SecurityContextHolder.getContext().setAuthentication(token);

                        filterChain.doFilter(request, response);
                    case temper:
                        // TODO 纳入到风控系统
                    case expired:
                        response.setStatus(HttpStatus.UNAUTHORIZED.value());  // 401
                        return;
                }
            }else {  // 没有传递jwt
                response.setStatus(HttpStatus.UNAUTHORIZED.value());  // 401
                return;
            }
        }
    }
}
